home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gxclutil.c,v 1.2.2.1 2000/11/09 23:36:53 rayjj Exp $ */
- /* Command list writing utilities. */
-
- #include "memory_.h"
- #include "string_.h"
- #include "gx.h"
- #include "gp.h"
- #include "gpcheck.h"
- #include "gserrors.h"
- #include "gxdevice.h"
- #include "gxdevmem.h" /* must precede gxcldev.h */
- #include "gxcldev.h"
- #include "gxclpath.h"
- #include "gsparams.h"
-
- /* ---------------- Statistics ---------------- */
-
- #ifdef DEBUG
- const char *const cmd_op_names[16] =
- {cmd_op_name_strings};
- private const char *const cmd_misc_op_names[16] =
- {cmd_misc_op_name_strings};
- private const char *const cmd_misc2_op_names[16] =
- {cmd_misc2_op_name_strings};
- private const char *const cmd_segment_op_names[16] =
- {cmd_segment_op_name_strings};
- private const char *const cmd_path_op_names[16] =
- {cmd_path_op_name_strings};
- const char *const *const cmd_sub_op_names[16] =
- {cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
- };
- struct stats_cmd_s {
- ulong op_counts[256];
- ulong op_sizes[256];
- ulong tile_reset, tile_found, tile_added;
- ulong same_band, other_band;
- } stats_cmd;
- extern ulong stats_cmd_diffs[5]; /* in gxclpath.c */
- int
- cmd_count_op(int op, uint size)
- {
- stats_cmd.op_counts[op]++;
- stats_cmd.op_sizes[op] += size;
- if (gs_debug_c('L')) {
- const char *const *sub = cmd_sub_op_names[op >> 4];
-
- if (sub)
- dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
- else
- dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
- size);
- fflush(dstderr);
- }
- return op;
- }
- void
- cmd_uncount_op(int op, uint size)
- {
- stats_cmd.op_counts[op]--;
- stats_cmd.op_sizes[op] -= size;
- }
- #endif
-
- /* Print statistics. */
- #ifdef DEBUG
- void
- cmd_print_stats(void)
- {
- int ci, cj;
-
- dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
- stats_cmd.tile_reset, stats_cmd.tile_found,
- stats_cmd.tile_added);
- dlprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
- stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
- stats_cmd_diffs[3], stats_cmd_diffs[4]);
- dlprintf2(" same_band = %lu, other_band = %lu\n",
- stats_cmd.same_band, stats_cmd.other_band);
- for (ci = 0; ci < 0x100; ci += 0x10) {
- const char *const *sub = cmd_sub_op_names[ci >> 4];
-
- if (sub != 0) {
- dlprintf1("[l] %s =", cmd_op_names[ci >> 4]);
- for (cj = ci; cj < ci + 0x10; cj += 2)
- dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
- sub[cj - ci],
- stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
- sub[cj - ci + 1],
- stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
- } else {
- ulong tcounts = 0, tsizes = 0;
-
- for (cj = ci; cj < ci + 0x10; cj++)
- tcounts += stats_cmd.op_counts[cj],
- tsizes += stats_cmd.op_sizes[cj];
- dlprintf3("[l] %s (%lu,%lu) =\n\t",
- cmd_op_names[ci >> 4], tcounts, tsizes);
- for (cj = ci; cj < ci + 0x10; cj++)
- if (stats_cmd.op_counts[cj] == 0)
- dputs(" -");
- else
- dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
- stats_cmd.op_sizes[cj]);
- }
- dputs("\n");
- }
- }
- #endif /* DEBUG */
-
- /* ---------------- Writing utilities ---------------- */
-
- /* Write the commands for one band or band range. */
- private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
- cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
- cmd_list * pcl, byte cmd_end)
- {
- const cmd_prefix *cp = pcl->head;
- int code_b = 0;
- int code_c = 0;
-
- if (cp != 0 || cmd_end != cmd_opv_end_run) {
- clist_file_ptr cfile = cldev->page_cfile;
- clist_file_ptr bfile = cldev->page_bfile;
- cmd_block cb;
- byte end = cmd_count_op(cmd_end, 1);
-
- if (cfile == 0 || bfile == 0)
- return_error(gs_error_ioerror);
- cb.band_min = band_min;
- cb.band_max = band_max;
- cb.pos = clist_ftell(cfile);
- if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
- band_min, band_max, cb.pos);
- clist_fwrite_chars(&cb, sizeof(cb), bfile);
- if (cp != 0) {
- pcl->tail->next = 0; /* terminate the list */
- for (; cp != 0; cp = cp->next) {
- #ifdef DEBUG
- if ((const byte *)cp < cldev->cbuf ||
- (const byte *)cp >= cldev->cend ||
- cp->size > cldev->cend - (const byte *)cp
- ) {
- lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
- return_error(gs_error_Fatal);
- }
- #endif
- clist_fwrite_chars(cp + 1, cp->size, cfile);
- }
- pcl->head = pcl->tail = 0;
- }
- clist_fwrite_chars(&end, 1, cfile);
- process_interrupts();
- code_b = clist_ferror_code(bfile);
- code_c = clist_ferror_code(cfile);
- if (code_b < 0)
- return_error(code_b);
- if (code_c < 0)
- return_error(code_c);
- }
- return code_b | code_c;
- }
-
- /* Write out the buffered commands, and reset the buffer. */
- int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
- cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
- {
- int nbands = cldev->nbands;
- gx_clist_state *pcls;
- int band;
- int code = cmd_write_band(cldev, cldev->band_range_min,
- cldev->band_range_max,
- &cldev->band_range_list, cmd_opv_end_run);
- int warning = code;
-
- for (band = 0, pcls = cldev->states;
- code >= 0 && band < nbands; band++, pcls++
- ) {
- code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
- warning |= code;
- }
- /* If an error occurred, finish cleaning up the pointers. */
- for (; band < nbands; band++, pcls++)
- pcls->list.head = pcls->list.tail = 0;
- cldev->cnext = cldev->cbuf;
- cldev->ccl = 0;
- #ifdef DEBUG
- if (gs_debug_c('l'))
- cmd_print_stats();
- #endif
- return_check_interrupt(code != 0 ? code : warning);
- }
-
- /*
- * Add a command to the appropriate band list, and allocate space for its
- * data. Return the pointer to the data area. If an error or (low-memory
- * warning) occurs, set cldev->error_code and return 0.
- */
- #define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
- byte *
- cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
- {
- byte *dp = cldev->cnext;
-
- if (size + cmd_headroom > cldev->cend - dp) {
- if ((cldev->error_code =
- cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
- if (cldev->error_code < 0)
- cldev->error_is_retryable = 0; /* hard error */
- else {
- /* upgrade lo-mem warning into an error */
- if (!cldev->ignore_lo_mem_warnings)
- cldev->error_code = gs_note_error(gs_error_VMerror);
- cldev->error_is_retryable = 1;
- }
- return 0;
- }
- else
- return cmd_put_list_op(cldev, pcl, size);
- }
- if (cldev->ccl == pcl) { /* We're adding another command for the same band. */
- /* Tack it onto the end of the previous one. */
- cmd_count_add1(stats_cmd.same_band);
- #ifdef DEBUG
- if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
- lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
- }
- #endif
- pcl->tail->size += size;
- } else {
- /* Skip to an appropriate alignment boundary. */
- /* (We assume the command buffer itself is aligned.) */
- cmd_prefix *cp = (cmd_prefix *)
- (dp + ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
-
- cmd_count_add1(stats_cmd.other_band);
- dp = (byte *) (cp + 1);
- if (pcl->tail != 0) {
- #ifdef DEBUG
- if (pcl->tail < pcl->head ||
- pcl->tail->size > dp - (byte *) (pcl->tail + 1)
- ) {
- lprintf1("cmd_put_list_op error at 0x%lx\n",
- (ulong) pcl->tail);
- }
- #endif
- pcl->tail->next = cp;
- } else
- pcl->head = cp;
- pcl->tail = cp;
- cldev->ccl = pcl;
- cp->size = size;
- }
- cldev->cnext = dp + size;
- return dp;
- }
- #ifdef DEBUG
- byte *
- cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
- {
- if_debug3('L', "[L]band %d: size=%u, left=%u",
- (int)(pcls - cldev->states),
- size, (uint) (cldev->cend - cldev->cnext));
- return cmd_put_list_op(cldev, &pcls->list, size);
- }
- #endif
-
- /* Add a command for a range of bands. */
- byte *
- cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
- uint size)
- {
- if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
- band_min, band_max, size,
- (uint)(cldev->cend - cldev->cnext));
- if (cldev->ccl != 0 &&
- (cldev->ccl != &cldev->band_range_list ||
- band_min != cldev->band_range_min ||
- band_max != cldev->band_range_max)
- ) {
- if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
- if (cldev->error_code < 0)
- cldev->error_is_retryable = 0; /* hard error */
- else {
- /* upgrade lo-mem warning into an error */
- cldev->error_code = gs_error_VMerror;
- cldev->error_is_retryable = 1;
- }
- return 0;
- }
- cldev->band_range_min = band_min;
- cldev->band_range_max = band_max;
- }
- return cmd_put_list_op(cldev, &cldev->band_range_list, size);
- }
-
- /* Write a variable-size positive integer. */
- int
- cmd_size_w(register uint w)
- {
- register int size = 1;
-
- while (w > 0x7f)
- w >>= 7, size++;
- return size;
- }
- byte *
- cmd_put_w(register uint w, register byte * dp)
- {
- while (w > 0x7f)
- *dp++ = w | 0x80, w >>= 7;
- *dp = w;
- return dp + 1;
- }
-
- /* Define the encodings of the different settable colors. */
- const clist_select_color_t
- clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
- clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
- clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
- clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
- int
- cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- const clist_select_color_t * select,
- gx_color_index color, gx_color_index * pcolor)
- {
- byte *dp;
- long diff = (long)color - (long)(*pcolor);
- byte op, op_delta2;
- int code;
-
- if (diff == 0)
- return 0;
- if (select->tile_color) {
- code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
- if (code < 0)
- return code;
- }
- op = select->set_op;
- op_delta2 = select->delta2_op;
- if (color == gx_no_color_index) {
- /*
- * We must handle this specially, because it may take more
- * bytes than the color depth.
- */
- code = set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
- if (code < 0)
- return code;
- } else {
- long delta;
- byte operand;
-
- switch ((cldev->color_info.depth + 15) >> 3) {
- case 5:
- if (!((delta = diff + cmd_delta1_32_bias) &
- ~cmd_delta1_32_mask) &&
- (operand =
- (byte) ((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
- operand != 15
- ) {
- code = set_cmd_put_op(dp, cldev, pcls,
- (byte) (op + operand), 2);
- if (code < 0)
- return code;
- dp[1] = (byte) (((delta >> 10) & 0300) +
- (delta >> 5) + delta);
- break;
- }
- if (!((delta = diff + cmd_delta2_32_bias) &
- ~cmd_delta2_32_mask)
- ) {
- code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
- if (code < 0)
- return code;
- dp[1] = (byte) ((delta >> 20) + (delta >> 16));
- dp[2] = (byte) ((delta >> 4) + delta);
- break;
- }
- code = set_cmd_put_op(dp, cldev, pcls, op, 5);
- if (code < 0)
- return code;
- *++dp = (byte) (color >> 24);
- goto b3;
- case 4:
- if (!((delta = diff + cmd_delta1_24_bias) &
- ~cmd_delta1_24_mask) &&
- (operand = (byte) (delta >> 16)) != 0 &&
- operand != 15
- ) {
- code = set_cmd_put_op(dp, cldev, pcls,
- (byte) (op + operand), 2);
- if (code < 0)
- return code;
- dp[1] = (byte) ((delta >> 4) + delta);
- break;
- }
- if (!((delta = diff + cmd_delta2_24_bias) &
- ~cmd_delta2_24_mask)
- ) {
- code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
- if (code < 0)
- return code;
- dp[1] = ((byte) (delta >> 13) & 0xf8) +
- ((byte) (delta >> 11) & 7);
- dp[2] = (byte) (((delta >> 3) & 0xe0) + delta);
- break;
- }
- code = set_cmd_put_op(dp, cldev, pcls, op, 4);
- if (code < 0)
- return code;
- b3: *++dp = (byte) (color >> 16);
- goto b2;
- case 3:
- code = set_cmd_put_op(dp, cldev, pcls, op, 3);
- if (code < 0)
- return code;
- b2: *++dp = (byte) (color >> 8);
- goto b1;
- case 2:
- if (diff >= -7 && diff < 7) {
- code = set_cmd_put_op(dp, cldev, pcls,
- op + (int)diff + 8, 1);
- if (code < 0)
- return code;
- break;
- }
- code = set_cmd_put_op(dp, cldev, pcls, op, 2);
- if (code < 0)
- return code;
- b1: dp[1] = (byte) color;
- }
- }
- *pcolor = color;
- return 0;
- }
-
- /* Put out a command to set the tile colors. */
- int
- cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- gx_color_index color0, gx_color_index color1)
- {
- int code = 0;
-
- if (color0 != pcls->tile_colors[0]) {
- code = cmd_put_color(cldev, pcls,
- &clist_select_tile_color0,
- color0, &pcls->tile_colors[0]);
- if (code != 0)
- return code;
- }
- if (color1 != pcls->tile_colors[1])
- code = cmd_put_color(cldev, pcls,
- &clist_select_tile_color1,
- color1, &pcls->tile_colors[1]);
- return code;
- }
-
- /* Put out a command to set the tile phase. */
- int
- cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- int px, int py)
- {
- int pcsize;
- byte *dp;
- int code;
-
- pcsize = 1 + cmd_size2w(px, py);
- code =
- set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
- if (code < 0)
- return code;
- ++dp;
- pcls->tile_phase.x = px;
- pcls->tile_phase.y = py;
- cmd_putxy(pcls->tile_phase, dp);
- return 0;
- }
-
- /* Write a command to enable or disable the logical operation. */
- int
- cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- int enable)
- {
- byte *dp;
- int code = set_cmd_put_op(dp, cldev, pcls,
- (byte)(enable ? cmd_opv_enable_lop :
- cmd_opv_disable_lop),
- 1);
-
- if (code < 0)
- return code;
- pcls->lop_enabled = enable;
- return 0;
- }
-
- /* Write a command to enable or disable clipping. */
- /* This routine is only called if the path extensions are included. */
- int
- cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- int enable)
- {
- byte *dp;
- int code = set_cmd_put_op(dp, cldev, pcls,
- (byte)(enable ? cmd_opv_enable_clip :
- cmd_opv_disable_clip),
- 1);
-
- if (code < 0)
- return code;
- pcls->clip_enabled = enable;
- return 0;
- }
-
- /* Write a command to set the logical operation. */
- int
- cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- gs_logical_operation_t lop)
- {
- byte *dp;
- uint lop_msb = lop >> 6;
- int code = set_cmd_put_op(dp, cldev, pcls,
- cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
-
- if (code < 0)
- return code;
- dp[1] = cmd_set_misc_lop + (lop & 0x3f);
- cmd_put_w(lop_msb, dp + 2);
- pcls->lop = lop;
- return 0;
- }
-
- /* Disable (if default) or enable the logical operation, setting it if */
- /* needed. */
- int
- cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- gs_logical_operation_t lop)
- {
- int code;
-
- if (lop == lop_default)
- return cmd_disable_lop(cldev, pcls);
- code = cmd_set_lop(cldev, pcls, lop);
- if (code < 0)
- return code;
- return cmd_enable_lop(cldev, pcls);
- }
-
- /* Write a parameter list */
- int /* ret 0 all ok, -ve error */
- cmd_put_params(gx_device_clist_writer *cldev,
- gs_param_list *param_list) /* NB open for READ */
- {
- byte *dp;
- int code;
- byte local_buf[512]; /* arbitrary */
- int param_length;
-
- /* Get serialized list's length + try to get it into local var if it fits. */
- param_length = code =
- gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
- if (param_length > 0) {
- /* Get cmd buffer space for serialized */
- code = set_cmd_put_all_op(dp, cldev, cmd_opv_put_params,
- 1 + sizeof(unsigned) + param_length);
- if (code < 0)
- return code;
-
- /* write param list to cmd list: needs to all fit in cmd buffer */
- if_debug1('l', "[l]put_params, length=%d\n", param_length);
- ++dp;
- memcpy(dp, ¶m_length, sizeof(unsigned));
- dp += sizeof(unsigned);
- if (param_length > sizeof(local_buf)) {
- int old_param_length = param_length;
-
- param_length = code =
- gs_param_list_serialize(param_list, dp, old_param_length);
- if (param_length >= 0)
- code = (old_param_length != param_length ?
- gs_note_error(gs_error_unknownerror) : 0);
- if (code < 0) {
- /* error serializing: back out by writing a 0-length parm list */
- memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
- cmd_shorten_list_op(cldev, &cldev->band_range_list,
- old_param_length);
- }
- } else
- memcpy(dp, local_buf, param_length); /* did this when computing length */
- }
- return code;
- }
-
- /* Initialize CCITTFax filters. */
- private void
- clist_cf_init(stream_CF_state *ss, int width)
- {
- ss->K = -1;
- ss->Columns = width;
- ss->EndOfBlock = false;
- ss->BlackIs1 = true;
- ss->DecodedByteAlign = align_bitmap_mod;
- }
- void
- clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem)
- {
- s_init_state((stream_state *)ss, &s_CFE_template, mem);
- s_CFE_set_defaults_inline(ss);
- clist_cf_init((stream_CF_state *)ss, width);
- s_CFE_template.init((stream_state *)(ss));
- }
- void
- clist_cfd_init(stream_CFD_state *ss, int width, int height, gs_memory_t *mem)
- {
- s_init_state((stream_state *)ss, &s_CFD_template, mem);
- s_CFD_template.set_defaults((stream_state *)ss);
- clist_cf_init((stream_CF_state *)ss, width);
- ss->Rows = height;
- s_CFD_template.init((stream_state *)(ss));
- }
-
- /* Initialize RunLength filters. */
- void
- clist_rle_init(stream_RLE_state *ss)
- {
- s_init_state((stream_state *)ss, &s_RLE_template, (gs_memory_t *)0);
- s_RLE_set_defaults_inline(ss);
- s_RLE_init_inline(ss);
- }
- void
- clist_rld_init(stream_RLD_state *ss)
- {
- s_init_state((stream_state *)ss, &s_RLD_template, (gs_memory_t *)0);
- s_RLD_set_defaults_inline(ss);
- s_RLD_init_inline(ss);
- }
-